package phonecompany;

import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;

import lint4j.p;

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import org.hamcrest.core.IsSame;

import phonecompany.account.Account;
import phonecompany.account.PayAsYouGoAccount;
import phonecompany.account.PhoneAccount;
import phonecompany.account.UnlimitedCallsAccount;
import phonecompany.customer.Customer;
import phonecompany.phone.Phone;
import phonecompany.phone.PhoneNumber;

/**
 * This class does most things for the whole system, it could also be deploy on
 * remote machine.
 * 
 * @since Oct 24, 2011
 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
 * @version $Id: PhoneManager.java 29 2011-10-30 21:54:06Z zexpp5@gmail.com $
 * 
 */
public class PhoneManager extends UnicastRemoteObject implements
		PhoneManagerService {
	private static PhoneManager phoneManager = null;
	private Map<PhoneNumber, Account> issuedPhone;

	private static Logger logger = Logger.getLogger(PhoneManager.class);

	static {
		DOMConfigurator.configure(PhoneManager.class
				.getResource("../ajp.log4j.xml"));
	}

	private PhoneManager() throws RemoteException {
		super();
	}

	/**
	 * This method use singleton model and used to create new PhoneManager
	 * object or get existed one.
	 * 
	 * @return new or existed PhoneManager object.
	 * @throws RemoteException
	 * @description
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 30, 2011 6:40:42 PM
	 */
	public static PhoneManager getPhoneManager() throws RemoteException {
		if (phoneManager == null) {
			logger.info("new PhoneManager created.");
			return new PhoneManager();

		}
		logger.info("get exist PhoneManager");
		return phoneManager;
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see phonecompany.PhoneManagerService#getAccount(phonecompany.phone.PhoneNumber)
	 */
	public Account getAccount(PhoneNumber phoneNumber) {
		Account acc = phoneManager.issuedPhone.get(phoneNumber);
		return acc;
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see phonecompany.PhoneManagerService#getAllAccount()
	 */
	public Map<PhoneNumber, Account> getAllAccount() {
		return issuedPhone;
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see phonecompany.PhoneManagerService#returnPhone(phonecompany.phone.PhoneNumber)
	 */
	public void returnPhone(PhoneNumber phoneNumber) {
		this.getAccount(phoneNumber).block();
		logger.info(phoneNumber + " is blocked");
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see phonecompany.PhoneManagerService#deleteAccount(phonecompany.phone.PhoneNumber)
	 */
	public boolean deleteAccount(PhoneNumber phoneNumber) {
		if (this.getAccount(phoneNumber).isBlocked()) {
			issuedPhone.remove(phoneNumber);
			return true;
		}
		return false;
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see phonecompany.PhoneManagerService#issueNewPhone(phonecompany.customer.Customer,
	 *      phonecompany.phone.PhoneNumber, java.lang.String)
	 */
	public Account issueNewPhone(Customer c, PhoneNumber pn, String accountType) {
		Account acc = null;
		if (accountType == "PayAsYouGo") {

			acc = new PayAsYouGoAccount(c, pn);

		} else if (accountType == "UnlimitedCallsAccount") {
			if (c.getCustomerAge() >= 18) {
				acc = new UnlimitedCallsAccount(c, pn);
			}
			logger.info("Customer under 18 not allowed to this account type.");
		} else {
			logger.info("void account type.");
		}

		Phone p = new Phone((PhoneAccount) acc);
		c.setPhone(p);
		issuedPhone.put(pn, acc);

		logger.info("a new phone " + pn + " was isssues to " + c);
		return acc;
	}

	/**
	 * 
	 * (non-Javadoc)
	 * 
	 * @see phonecompany.PhoneManagerService#echoPhoneAccount(java.lang.String)
	 */
	public Account echoPhoneAccount(String phoneNumber) {

		Account acc = this.getAccount(new PhoneNumber(phoneNumber));
		try {
			UnicastRemoteObject.exportObject((Remote) acc);
			logger.info("account echoed.");
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return acc;

	}

	/**
	 * `The main method. When the PhoneManager is deployed on RMI, this method
	 * will do the registry stuffs.
	 * 
	 * @param args
	 * @description
	 * 
	 * @author <a href="mailto:zexpp5@gmail.com">Zexu.Lin</a>
	 * @update Oct 30, 2011 6:55:41 PM
	 */
	public static void main(String[] args) {
		Registry r;
		try {
			r = LocateRegistry.getRegistry();
			r.bind("PhoneManagerService", getPhoneManager());
			logger.info("PhoneManager registed and binded to PhoneManagerService");
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (AlreadyBoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}
